// ==++==
// 
//   
//    Copyright (c) 2006 Microsoft Corporation.  All rights reserved.
//   
//    The use and distribution terms for this software are contained in the file
//    named license.txt, which can be found in the root of this distribution.
//    By using this software in any fashion, you are agreeing to be bound by the
//    terms of this license.
//   
//    You must not remove this notice, or any other, from this software.
//   
// 
// ==--==
/******************************************************************************

Module Name:

    codeman.h

Abstract:

    Wrapper to facilitate multiple JITcompiler support in the COM+ Runtime

    The ExecutionManager is responsible for managing the RangeSections.
    Given an IP, it can find the RangeSection which holds that IP.

    RangeSections contain the JITed codes. Each RangeSection knows the 
    IJitManager which created it.

    An IJitManager knows about which method bodies live in each RangeSection.
    It can handle methods of one given CodeType. It can map a method body to
    a MethodDesc. It knows where the GCInfo about the method lives.
    Today, we have 3 IJitManagers viz.
    1. EEJitManager for JITcompiled code generated by mscorjit.dll
    2. MNativeJitManager for ngenned code. We should be able to replace
       this with EEJitManager

    An ICodeManager knows how to crack a specific format of GCInfo. There is
    a default format (handled by ExecutionManager::GetDefaultCodeManager())
    which can be shared by different IJitManagers/IJitCompilers.

    An ICorJitCompiler knows how to generate code for a method IL, and produce
    GCInfo in a format which the corresponding IJitManager's ICodeManager 
    can handle.

                                               ExecutionManager
                                                       |
                           +-----------+---------------+---------------+-----------+--- ...
                           |           |                               |           |
                        CodeType       |                            CodeType       |
                           |           |                               |           |
                           v           v                               v           v
+---------------+      +--------+<---- R    +---------------+      +--------+<---- R
|ICorJitCompiler|<---->|IJitMan |<---- R    |ICorJitCompiler|<---->|IJitMan |<---- R
+---------------+      +--------+<---- R    +---------------+      +--------+<---- R
                           |       x   .                               |       x   .
                           |        \  .                               |        \  .
                           v         \ .                               v         \ .
                       +--------+      R                           +--------+      R
                       |ICodeMan|                                  |ICodeMan|     (RangeSections)
                       +--------+                                  +--------+       

******************************************************************************/

#ifndef __CODEMAN_HPP__

#define __CODEMAN_HPP__

// this is the define the make ejitted code recognizable from regular jit even though they are
// both IL.

#define   miManaged_IL_EJIT             (miMaxMethodImplVal + 1)

#include "crst.h"
#include "eetwain.h"
#ifdef FJIT
#include "fjit_eetwain.h"
#endif
#include "ceeload.h"
#include "jitinterface.h"
#include "debuginfostore.h"
#include "shash.h"

class MethodDesc;
class ICorJitCompiler;
class IJitManager;
class EEJitManager;
class ExecutionManager;
class Thread;
class CrawlFrame;
class MethodEntryChunk;
class IDebugInfoStore;
struct JitDebugInfo;
struct EE_ILEXCEPTION;
struct EE_ILEXCEPTION_CLAUSE;
typedef unsigned EH_CLAUSE_ENUMERATOR;

inline DWORD MIN (DWORD a, DWORD b);



// Note PAGE_SIZE is 0x1000 (4096) on X86 
//               and 0x2000 (8192) on IA64

#define PAGE_MASK               (PAGE_SIZE-1)
#define PAGE_ALIGN              ~(PAGE_MASK)
#define ROUND_DOWN_TO_PAGE(x)   ( (size_t) (x)              & PAGE_ALIGN)
#define ROUND_UP_TO_PAGE(x)     (((size_t) (x) + PAGE_MASK) & PAGE_ALIGN)


//-----------------------------------------------------------------------------
// Holds Jit (not ngen) debugging information manipulated by the EEJitManager.

typedef DPTR(struct JitDebugInfo) PTR_JitDebugInfo;

struct JitDebugInfo
{
    void Init()
    {
    }
    CompressDebugInfo::Boundaries m_bounds;
    CompressDebugInfo::Vars       m_vars;  

#ifdef DACCESS_COMPILE
    void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
#endif
};

//-----------------------------------------------------------------------------
// Method header which exists just before the code.
// Every IJitManager could have its own format for the header. However,
// everyone just used CodeHeader.
// MNativeJitManager use CORCOMPILE_METHOD_HEADER, however, that is a superset
// of CodeHeader, and we may eventually get rid of MNativeJitManager.

#ifdef USE_INDIRECT_CODEHEADER
typedef DPTR(struct _hpRealCodeHdr) PTR_RealCodeHeader;
typedef DPTR(struct _hpCodeHdr) PTR_CodeHeader;

#else // USE_INDIRECT_CODEHEADER
typedef DPTR(struct _hpCodeHdr) PTR_CodeHeader;

#endif // USE_INDIRECT_CODEHEADER

#ifdef USE_INDIRECT_CODEHEADER
typedef struct _hpRealCodeHdr
#else // USE_INDIRECT_CODEHEADER
typedef struct _hpCodeHdr
#endif // USE_INDIRECT_CODEHEADER
{
public:
    // On _Win64, this byte serves as padding to make
    // the layout of CodeHeader match that used by the _WIN64 implementation of CORCOMPILE_METHOD_HEADER
    PTR_JitDebugInfo     phdrDebugInfo;
    
    // Note - *(&(pCodeHeader->phdrJitEHInfo) - sizeof(size_t)) 
    // contains the number of EH clauses, See EEJitManager::allocEHInfo
    PTR_EE_ILEXCEPTION phdrJitEHInfo;
    BYTE *             phdrJitGCInfo;


    // Also see CORCOMPILE_METHOD_HEADER for the layout of the NGEN code header
    //
    PTR_MethodDesc   phdrMDesc;

public:
    //
    // Note: that the JITted code follows immediately after the MethodDesc*
    //
#ifndef USE_INDIRECT_CODEHEADER
    PTR_JitDebugInfo        GetDebugInfo()
    {
        return phdrDebugInfo;
    }
    PTR_EE_ILEXCEPTION      GetEHInfo()
    {
        return phdrJitEHInfo;
    }
    BYTE*                   GetGCInfo()
    {
        return phdrJitGCInfo;
    }
    PTR_MethodDesc          GetMethodDesc()
    {
        return phdrMDesc;
    }
    BYTE*                   GetCodeStartAddress()
    {
        return ((BYTE*)PTR_HOST_TO_TADDR(this) + sizeof(CodeHeader));
//        return (BYTE*)PTR_TO_TADDR(PTR_CodeHeader((CodeHeader*)this)) + sizeof(CodeHeader);
    }

    void SetRealCodeHeader(BYTE* pRCH)
    {
        // do nothing when we don't use an indirect header
        return;
    }

    void SetDebugInfo(PTR_JitDebugInfo pDI)
    {
        phdrDebugInfo = pDI;
    }
    void SetEHInfo(PTR_EE_ILEXCEPTION pEH)
    {
        phdrJitEHInfo = pEH;
    }
    void SetGCInfo(BYTE* pGC)
    {
        phdrJitGCInfo = pGC;
    }
    void SetMethodDesc(PTR_MethodDesc pMD)
    {
        phdrMDesc = pMD;
    }
#endif // !USE_INDIRECT_CODEHEADER

// if we're using the indirect codeheaders then all enumeration is done by the code header
#ifndef USE_INDIRECT_CODEHEADER
#ifdef DACCESS_COMPILE
    void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan);
#endif  // DACCESS_COMPILE
#endif  // USE_INDIRECT_CODEHEADER
#ifdef USE_INDIRECT_CODEHEADER
} RealCodeHeader;
#else // USE_INDIRECT_CODEHEADER
} CodeHeader;
#endif // USE_INDIRECT_CODEHEADER

#ifdef USE_INDIRECT_CODEHEADER
typedef struct _hpCodeHdr
{
    PTR_RealCodeHeader   pRealCodeHeader;

public:
    PTR_JitDebugInfo        GetDebugInfo()
    {
        return pRealCodeHeader->phdrDebugInfo;
    }
    PTR_EE_ILEXCEPTION      GetEHInfo()
    {
        return pRealCodeHeader->phdrJitEHInfo;
    }
    BYTE*                   GetGCInfo()
    {
        return pRealCodeHeader->phdrJitGCInfo;
    }
    PTR_CodeHeader          GetNextFuncletHeader()
    {
        return pRealCodeHeader->pNextFuncletHeader;
    }
    PTR_RUNTIME_FUNCTION    GetUnwindInfo()
    {
        return pRealCodeHeader->pUnwindInfo;
    }
    PTR_MethodDesc          GetMethodDesc()
    {
        return pRealCodeHeader->phdrMDesc;
    }
    BYTE*                   GetCodeStartAddress()
    {        
        return ((BYTE*)PTR_HOST_TO_TADDR(this) + sizeof(CodeHeader));
    }
    PTR_CORCOMPILE_METHOD_COLD_HEADER GetColdHeader()
    {
        return pRealCodeHeader->pColdHeader;
    }

    void SetRealCodeHeader(BYTE* pRCH)
    {
        pRealCodeHeader = PTR_RealCodeHeader((RealCodeHeader*)pRCH);
    }

    void SetDebugInfo(PTR_JitDebugInfo pDI)
    {
        pRealCodeHeader->phdrDebugInfo = pDI;
    }
    void SetEHInfo(PTR_EE_ILEXCEPTION pEH)
    {
        pRealCodeHeader->phdrJitEHInfo = pEH;
    }
    void SetGCInfo(BYTE* pGC)
    {
        pRealCodeHeader->phdrJitGCInfo = pGC;
    }
    void SetNextFuncletHeader(PTR_CodeHeader pNext)
    {
        pRealCodeHeader->pNextFuncletHeader = pNext;
    }
    void SetUnwindInfo(PTR_RUNTIME_FUNCTION pUnwind)
    {
        pRealCodeHeader->pUnwindInfo = pUnwind;
    }
    void SetMethodDesc(PTR_MethodDesc pMD)
    {
        pRealCodeHeader->phdrMDesc = pMD;
    }
    void SetColdHeader(PTR_CORCOMPILE_METHOD_COLD_HEADER pColdHeader)
    {
        pRealCodeHeader->pColdHeader = pColdHeader;
    }

#ifdef DACCESS_COMPILE
    void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan);
#endif  // DACCESS_COMPILE
} CodeHeader;
#endif // USE_INDIRECT_CODEHEADER


//-----------------------------------------------------------------------------
// This is a structure used to consolidate the information that we 
// need we creating new code heaps. 
// When creating new JumpStubs we have a constarint that the address used
// should be in the range [loAddr..hiAddr]
//
struct CodeHeapRequestInfo
{
    MethodDesc * m_pMD;
    BaseDomain * m_pDomain;
    const BYTE * m_loAddr;          // lowest address to use to satisfy our request (0 -- don't care)
    const BYTE * m_hiAddr;          // hihest address to use to satisfy our request (0 -- don't care)
    size_t       m_requestSize;     // minimum size that must be made available
    size_t       m_reserveSize;     // Amount that VirtualAlloc will reserved
    size_t       m_cacheSize;
    bool         m_isDynamicDomain;
    
    bool   IsDynamicDomain()                    { return m_isDynamicDomain;    }
    
    size_t getRequestSize()                     { return m_requestSize;        }
    void   setRequestSize(size_t requestSize)   { m_requestSize = requestSize; }
    
    size_t getReserveSize()                     { return m_reserveSize;        }
    void   setReserveSize(size_t reserveSize)   { m_reserveSize = reserveSize; }
    
    size_t getCacheSize()                       { return m_cacheSize;          }
    void   setCacheSize(size_t cacheSize)       { m_cacheSize = cacheSize;     }
    
    void   Init();
    
    CodeHeapRequestInfo(MethodDesc *pMD)
        : m_pMD(pMD), m_pDomain(0), 
          m_loAddr(0), m_hiAddr(0),
          m_requestSize(0), m_reserveSize(0), m_cacheSize(0)
    {   Init(); }
    
    CodeHeapRequestInfo(MethodDesc *pMD, BaseDomain *pDomain, size_t requestSize,
                        BYTE * loAddr, BYTE * hiAddr)
        : m_pMD(pMD), m_pDomain(pDomain), 
          m_loAddr(loAddr), m_hiAddr(hiAddr),
          m_requestSize(requestSize), m_reserveSize(0), m_cacheSize(0)
    {   Init(); }
};

//-----------------------------------------------------------------------------
//
// A CodeHeap is the abstraction the IJitManager uses to allocate memory
// needed to the jitting of a method.
// The CodeHeap works together with the HeapList to manage a contiguous block of memory.
// The CodeHeap is a non growable chunk of memory (it can be reserved and
// committed on demand).
//
// A CodeHeap is naturally protected from multiple threads by the code heap
// critical section - m_pCodeHeapCritSec - so if the implementation of the heap
// is only for the code manager, no locking needs to occur.
// It's important however that a delete operation on the CodeHeap (if any) happens
// via EEJitManager::ReleaseReferenceToHeap(CodeHeap*, MethodDesc*)
//
// The heap to be created depends on the MethodDesc that is being compiled. 
// Standard code uses the LoaderCodeHeap, a heap based on the LoaderHeap.
// DynamicMethods - and only those - use a HostCodeHeap, a heap that does
// normal Alloc/Free so reclamation can be performed. 
//
// The convention is that every heap implementation would have a static create
// function that returns a HeapList. The HeapList *must* be properly initialized
// on return except for the next pointer
//

typedef VPTR(class CodeHeap) PTR_CodeHeap;

class CodeHeap
{
    VPTR_BASE_VTABLE_CLASS(CodeHeap)

public:

#ifdef DACCESS_COMPILE
    CodeHeap() {}
#endif

    // virtual dtor. Clean up heap
    virtual ~CodeHeap() {}

    // Alloc the specified numbers of bytes.
    // There are only 2 flavors of Alloc that the CodeHeap cares about: a throw and a non-throw.
    // We could combine them together and use a flag to call one or the other but the overall model
    // appears to favor explicit naming convention.
    virtual void* AllocMemory(size_t size, DWORD alignment) = 0;
    virtual void* AllocMemory_NoThrow(size_t size, DWORD alignment) = 0;

    // the inital address of the CodeHeap
    virtual void* GetHeapStartAddress() = 0;

#ifdef _DEBUG
    // for assert usage only. Return whatever internal data is used in the CodeHeap on return from Create.
    // Typically this value minus the start address in the HeapList should return the heap start address
    virtual size_t GetReservedPrivateData() = 0;
#endif

#ifdef DACCESS_COMPILE
    virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) = 0;
#endif

protected:
    friend class EEJitManager;
    // allows for reclamation of methods from the heap. Not every MethodDesc asks to be reclaimed
    // and a heap is free to ignore the request.
    // However for locking reasons is important this method is not called directly (hence protected) 
    // but always via the EEJitManager::ReleaseReferenceToHeap(CodeHeap*, MethodDesc*)
    virtual void ReleaseReferenceToHeap(MethodDesc* pMD) = 0;
    virtual void DestroyHeap() = 0;

};

//-----------------------------------------------------------------------------
// The HeapList works together with the CodeHeap to manage a contiguous block of memory.
//
// A single HeapList contains code only for a single AppDomain. EEJitManager uses
// EEJitManager::DomainCodeHeapList to keep a list of HeapLists for each AppDomain.

typedef DPTR(struct _HeapList) PTR_HeapList;

typedef struct _HeapList
{
    PTR_HeapList        hpNext;
    PTR_CodeHeap        pHeap;
    
    TADDR               startAddress;
    TADDR               endAddress;     // the current end of the used portion of the Heap

    // Counters which are incremented by writers.
    // Readers can check that changeEnd before the read is the same as
    // changeStart after the read to ensure that no writer was stomping
    // on the heap while they were reading it
    volatile PBYTE      changeStart;
    volatile PBYTE      changeEnd;

    TADDR               mapBase;        // "startAddress" rounded down to PAGE_SIZE. pHdrMap is relative to this address
    PTR_DWORD           pHdrMap;        // bit array used to find the start of methods

    size_t              maxCodeHeapSize;// Size of the entire contiguous block of memory
    DWORD               cBlocks;        // Number of allocations
    DWORD /*volatile*/  bFull;          // Heap is considered full do not use for new allocations
    
    // We have a hashtable cache to map from an address to a HeapList
    // This allows us to look up frequently used HeapLists faster.
    PBYTE               pCacheSpacePtr;
    size_t              bCacheSpaceSize;


    PTR_HeapList GetVolatile_hpNext()
    { return hpNext; }

    void SetVolatile_hpNext(PTR_HeapList next)
    { hpNext = next; }

    void SetHeapFull() 
    { *((volatile DWORD *) &bFull) = TRUE; }

    bool IsHeapFull() 
    { return (*((volatile DWORD *) &bFull) != 0); }

} HeapList;

//-----------------------------------------------------------------------------
// Implementation of the standard CodeHeap.
// Use the ExplicitControlLoaderHeap for allocations
// (Check the base class above - CodeHeap - for comments on the functions)
//
typedef VPTR(class LoaderCodeHeap) PTR_LoaderCodeHeap;

class LoaderCodeHeap : CodeHeap
{
#ifdef DACCESS_COMPILE
    friend class ClrDataAccess;
#endif
    
    VPTR_VTABLE_CLASS(LoaderCodeHeap, CodeHeap)

private:
    PTR_ExplicitControlLoaderHeap pLoaderHeap;

    LoaderCodeHeap(ExplicitControlLoaderHeap *pHeap)
    {
        LEAF_CONTRACT;
        pLoaderHeap = PTR_ExplicitControlLoaderHeap(pHeap);
    }

public:
    static HeapList* CreateCodeHeap(CodeHeapRequestInfo *pInfo, LoaderHeap *pJitMetaHeap);

public:
    virtual ~LoaderCodeHeap() 
    {
#ifndef DACCESS_COMPILE
        WRAPPER_CONTRACT;
        if (pLoaderHeap) 
            delete pLoaderHeap;
#endif
    }

    virtual void* AllocMemory(size_t size, DWORD alignment)
    {
#ifndef DACCESS_COMPILE
        WRAPPER_CONTRACT;
        return (void*)pLoaderHeap->AllocAlignedmem(size, alignment, FALSE);
#else
        return NULL;
#endif
    }

    virtual void* AllocMemory_NoThrow(size_t size, DWORD alignment)
    {
#ifndef DACCESS_COMPILE
        WRAPPER_CONTRACT;
        return (void*)pLoaderHeap->AllocAlignedmem_NoThrow(size, alignment, FALSE);
#else
        return NULL;
#endif
    }

    virtual void* GetHeapStartAddress() 
    {
        WRAPPER_CONTRACT;
        return pLoaderHeap->GetFirstBlockVirtualAddress();
    }

#ifdef _DEBUG
    virtual size_t GetReservedPrivateData()
    {
        LEAF_CONTRACT;
        return sizeof(HeapList) + sizeof(LoaderHeapBlock);
    }
#endif

#ifdef DACCESS_COMPILE
    virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
    {
        WRAPPER_CONTRACT;
        pLoaderHeap->EnumMemoryRegions(flags);
    }
#endif

protected:
    // the LoaderHeap does not allow for reclamation of methods
    virtual void ReleaseReferenceToHeap(MethodDesc* pMD) {LEAF_CONTRACT;}
    virtual void DestroyHeap() {LEAF_CONTRACT;}

};

//-----------------------------------------------------------------------------
// The ExecutionManager uses RangeSection ss the abstration of a contiguous
// address range to track the code heaps.

typedef DPTR(struct _rangesection) PTR_RangeSection;

typedef struct _rangesection
{
    TADDR               LowAddress;
    TADDR               HighAddress;

    PTR_IJitManager     pjit;           // The owner of this address range
    TADDR               ptable;

    PTR_RangeSection    pnext;          // link rangesections in a sorted list
    PTR_RangeSection    pLastUsed;      // for the head node only:  a link to rangesections that was used most recently

    DWORD               flags;
    PTR_RangeSection    pcold;          // pointer to cold range section (only present in hot range sections)
    PTR_Module          pModule;        // only valid for zapped images where a range section only contains code from one module

} RangeSection;

#define RANGE_SECTION_COLD  0x01

/*****************************************************************************/

#define FAILED_JIT      0x01
#define FAILED_EJIT     0x02

#define MIH_GC_OFFSET (offsetof(IMAGE_COR_MIH_ENTRY, MIHData) - offsetof(IMAGE_COR_MIH_ENTRY, Flags))

// METHODTOKEN == CORCOMPILE_METHOD_HEADER* for managed native code
//             == CodeHeader* for EEJitManager
typedef struct _METHODTOKEN {
    inline PTR_CodeHeader GetCodeHeader()
    {
        LEAF_CONTRACT;
        return PTR_CodeHeader((CodeHeader*)this);
    }
} *METHODTOKEN;

struct JumpStubBlockHeader;

//-----------------------------------------------------------------------------
//
// Manages the CodeHeap for some of the RangeSections in the ExecutionManager
//
//-----------------------------------------------------------------------------

class IJitManager 
{
    VPTR_BASE_VTABLE_CLASS(IJitManager)
    
public:

    struct MethodRegionInfo
    {
        BYTE *hotStartAddress;
        size_t hotSize;
        BYTE *coldStartAddress;
        size_t coldSize;
    };

    enum ScanFlag    {ScanReaderLock, ScanNoReaderLock};

#ifndef DACCESS_COMPILE
    IJitManager();
    virtual ~IJitManager();
#endif // #ifndef DACCESS_COMPILE

    // Get an DebugInfoStore, which lets us access jit information.
    virtual void GetDebugInfoStore(IDebugInfoStore ** ppStore) = 0;

#ifndef DACCESS_COMPILE   
    // Used to populate the info store.
    // The calls do not own the arrays passed in. It is expected that the implementations will compress
    // the arrays, and thus not need the uncompressed copy that was passed in.
    virtual void setVars(CodeHeader * pHeader, CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars) = 0;
    virtual void setBoundaries(CodeHeader * pHeader, CORINFO_METHOD_HANDLE ftn, ULONG32 cMap, ICorDebugInfo::OffsetMapping *pMap) = 0;
#endif    

    virtual void JitCodeToMethodInfo(
            SLOT currentPC,
            MethodDesc** ppMethodDesc,
            METHODTOKEN* pMethodToken = NULL,
            DWORD* pPCOffset = NULL,
            ScanFlag scanFlag = ScanReaderLock) = 0;

    virtual MethodDesc* JitTokenToMethodDesc(METHODTOKEN MethodToken)=0;
    virtual BYTE*       JitTokenToStartAddress(METHODTOKEN MethodToken, ScanFlag scanFlag=ScanReaderLock)=0;
    virtual size_t      JitTokenToMethodHotSize(METHODTOKEN MethodToken)=0;
    virtual void        JitTokenToMethodRegionInfo(METHODTOKEN MethodToken, MethodRegionInfo *methodRegionInfo) = 0;
    virtual unsigned    InitializeEHEnumeration(METHODTOKEN MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState)=0;
    virtual EE_ILEXCEPTION_CLAUSE* GetNextEHClause(METHODTOKEN MethodToken,
                                        EH_CLAUSE_ENUMERATOR* pEnumState, 
                                        EE_ILEXCEPTION_CLAUSE* pEHclause)=0; 
#ifndef DACCESS_COMPILE    
    virtual TypeHandle  ResolveEHClause(METHODTOKEN MethodToken,
                                        EH_CLAUSE_ENUMERATOR* pEnumState, 
                                        EE_ILEXCEPTION_CLAUSE* pEHClauseOut,
                                        CrawlFrame *pCf)=0;
#endif // #ifndef DACCESS_COMPILE
    virtual void*       GetGCInfo(METHODTOKEN MethodToken)=0;
#ifndef DACCESS_COMPILE
    virtual void        RemoveJitData(METHODTOKEN MethodToken, size_t GCinfo_len, size_t EHinfo_len)=0;
    virtual void        Unload(AppDomain *pDomain)=0;   // for appdomain unloading
    virtual BOOL        LoadJIT(LPCWSTR szJITdll);
    virtual void        ResumeAtJitEH   (CrawlFrame* pCf, EE_ILEXCEPTION_CLAUSE *EHClausePtr, DWORD nestingLevel, Thread *pThread, BOOL unwindStack)=0;
    virtual int         CallJitEHFilter (CrawlFrame* pCf, EE_ILEXCEPTION_CLAUSE *EHClausePtr, DWORD nestingLevel, OBJECTREF thrownObj)=0;
    virtual void        CallJitEHFinally(CrawlFrame* pCf, EE_ILEXCEPTION_CLAUSE *EHClausePtr, DWORD nestingLevel)=0;

    virtual CodeHeader*         allocCode(MethodDesc* pFD, size_t blockSize, CorJitAllocMemFlag flag)=0;
#endif // #ifndef DACCESS_COMPILE


#ifndef DACCESS_COMPILE
    virtual BYTE *              allocGCInfo(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize)=0;
    virtual EE_ILEXCEPTION*     allocEHInfo(CodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize)=0;
    virtual JumpStubBlockHeader* allocJumpStubBlock(MethodDesc* pMD, DWORD numJumps, 
                                                    BYTE * loAddr, BYTE * hiAddr,
                                                    BaseDomain *pDomain)=0;
#endif // #ifndef DACCESS_COMPILE

#ifndef DACCESS_COMPILE
    virtual BYTE* GetNativeEntry(BYTE* startAddress)=0;
#endif // #ifndef DACCESS_COMPILE

    static ScanFlag GetScanFlags();



#ifdef DACCESS_COMPILE
    virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
#endif

#ifndef DACCESS_COMPILE
    void SetCodeManager(ICodeManager *codeMgr, BOOL bIsDefault)
    {
        LEAF_CONTRACT;

        m_runtimeSupport = codeMgr;
        m_IsDefaultCodeMan = bIsDefault;
        return;
    }
#endif

    ICodeManager *GetCodeManager() 
    {
        LEAF_CONTRACT;

        return m_runtimeSupport;
    }

    void SetCodeType(DWORD type)
    {
        LEAF_CONTRACT;

        m_CodeType = type;
        return;
    }

    DWORD GetCodeType()
    {
        LEAF_CONTRACT;

        return(m_CodeType);
    }

    BOOL IsJitForType(DWORD type)
    {
        LEAF_CONTRACT;

        if (type == m_CodeType)
            return TRUE;
        else
            return FALSE;
    }
    
    BOOL IsJitLoaded()
    {
        LEAF_CONTRACT;

        return (m_jit != NULL);
    }

    VOID ClearCache()
    {
        if( m_jit != NULL )
        {
            m_jit->clearCache();
        }
    }

    BOOL IsCacheCleanupRequired()
    {
        if( m_jit != NULL )
        {
            return m_jit->isCacheCleanupRequired();
        }

        return FALSE;
    }

    ICorJitCompiler *  m_jit;
    PTR_IJitManager    m_next;

protected:

    DWORD            m_CodeType;
    DWORD            m_IsDefaultCodeMan;
    PTR_ICodeManager m_runtimeSupport;
    HINSTANCE        m_JITCompiler;
};

//-----------------------------------------------------------------------------

struct JumpStubBlockHeader
{
    JumpStubBlockHeader *  m_next;
    UINT32                 m_used;
    UINT32                 m_allocated;
    BaseDomain *           m_domain;
    UINT64                 m_zero;
};

//-----------------------------------------------------------------------------
// Ideally, EEJitManager would just implement IDebugInfoStore directly, but DAC
// doesn't support multiple inheritence.
// The only thing in here is a VTable.
// This is conceptually an extension to EEJitManager

class EEJitDebugInfoStore : public IDebugInfoStore
{
public:
    VPTR_VTABLE_CLASS(EEJitDebugInfoStore, IDebugInfoStore)

    EEJitDebugInfoStore() { }
    
    static CodeHeader * EEJitDebugInfoStore::GetCodeHeaderFromJitRequest(const DebugInfoRequest & request);

    virtual HRESULT GetVars(
        const DebugInfoRequest & request,
        IN FP_IDS_NEW fpNew, IN void * pNewData,
        OUT ULONG32 * pcVars, 
        OUT ICorDebugInfo::NativeVarInfo ** ppVars);
    virtual HRESULT GetBoundaries(
        const DebugInfoRequest & request,
        IN FP_IDS_NEW fpNew, IN void * pNewData,
        OUT ULONG32 * pcMap, 
        OUT ICorDebugInfo::OffsetMapping ** ppMap);

#ifdef DACCESS_COMPILE
    virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD);
#endif        
};


/*****************************************************************************/

#if defined (_MSC_VER) && _MSC_VER <= 1300
template void DoNothing(EEJitManager*);
template BOOL CompareDefault(EEJitManager*,EEJitManager*);
typedef DacHolder<EEJitManager *, DoNothing, DoNothing> HACKEEJitManagerLockHolder;
#endif

typedef VPTR(class EEJitManager) PTR_EEJitManager;

class EEJitManager :public IJitManager
{
#ifdef DACCESS_COMPILE
    friend class ClrDataAccess;
#endif
    friend class CheckDuplicatedStructLayouts;
    friend class EEJitDebugInfoStore;

    VPTR_VTABLE_CLASS(EEJitManager, IJitManager)
    
public:

#ifndef DACCESS_COMPILE
    EEJitManager();

    // No destructor necessary. Only one instance of this class that is destroyed at process shutdown.
    // ~EEJitManager();
#endif // #ifndef DACCESS_COMPILE

    // Used to get a reader interface for the stores.
    virtual void GetDebugInfoStore(IDebugInfoStore ** ppStore);

#ifndef DACCESS_COMPILE       
    // Used to populate the info store.
    virtual void setVars(CodeHeader * pHeader, CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars);
    virtual void setBoundaries(CodeHeader * pHeader, CORINFO_METHOD_HANDLE ftn, ULONG32 cMap, ICorDebugInfo::OffsetMapping *pMap);
#endif
    
    virtual void JitCodeToMethodInfo(SLOT currentPC, 
                                     MethodDesc** ppMethodDesc, 
                                     METHODTOKEN* pMethodToken=NULL, 
                                     DWORD* pPCOffset=NULL, 
                                     ScanFlag scanFlag=ScanReaderLock);
    virtual MethodDesc* JitTokenToMethodDesc(METHODTOKEN MethodToken);
    static  BYTE*       JitTokenToStartAddressStatic(METHODTOKEN MethodToken, ScanFlag scanFlag=ScanReaderLock);
    virtual BYTE*       JitTokenToStartAddress(METHODTOKEN MethodToken, ScanFlag scanFlag=ScanReaderLock);
    virtual size_t      JitTokenToMethodHotSize(METHODTOKEN MethodToken);
    virtual void        JitTokenToMethodRegionInfo(METHODTOKEN MethodToken, MethodRegionInfo *methodRegionInfo);

    virtual unsigned    InitializeEHEnumeration(METHODTOKEN MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState);
    virtual EE_ILEXCEPTION_CLAUSE*      GetNextEHClause(METHODTOKEN MethodToken,
                                        EH_CLAUSE_ENUMERATOR* pEnumState, 
                                        EE_ILEXCEPTION_CLAUSE* pEHclause); 
#ifndef DACCESS_COMPILE    
    virtual TypeHandle  ResolveEHClause(METHODTOKEN MethodToken,
                                        EH_CLAUSE_ENUMERATOR* pEnumState, 
                                        EE_ILEXCEPTION_CLAUSE* pEHClauseOut,
                                        CrawlFrame *pCf);
#endif // #ifndef DACCESS_COMPILE
    void*               GetGCInfo(METHODTOKEN MethodToken);
#ifndef DACCESS_COMPILE
    virtual void        RemoveJitData(METHODTOKEN MethodToken, size_t GCinfo_len, size_t EHinfo_len);

    virtual void        Unload(AppDomain *pDomain);
    virtual void        ResumeAtJitEH   (CrawlFrame* pCf, EE_ILEXCEPTION_CLAUSE *EHClausePtr, DWORD nestingLevel, Thread *pThread, BOOL unwindStack);
    virtual int         CallJitEHFilter (CrawlFrame* pCf, EE_ILEXCEPTION_CLAUSE *EHClausePtr, DWORD nestingLevel, OBJECTREF thrownObj);
    virtual void        CallJitEHFinally(CrawlFrame* pCf, EE_ILEXCEPTION_CLAUSE *EHClausePtr, DWORD nestingLevel);

    CodeHeader*         allocCode(MethodDesc* pFD, size_t blockSize, CorJitAllocMemFlag flag);
    void                allocEntryChunk(MethodDescChunk *pMDChunk);
    BYTE *              allocGCInfo(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize);
    EE_ILEXCEPTION*     allocEHInfo(CodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize);
    JumpStubBlockHeader* allocJumpStubBlock(MethodDesc* pMD, DWORD numJumps, 
                                            BYTE * loAddr, BYTE * hiAddr,
                                            BaseDomain *pDomain);

#endif // #ifndef DACCESS_COMPILE

    inline virtual BOOL IsStub(const BYTE* address)
    { // This is needed by the debugger, this code manager does not produce stubs, so always return false 
        LEAF_CONTRACT;
        return false;
    }

    inline virtual const BYTE* FollowStub(const BYTE* address)
    {
        LEAF_CONTRACT;
        _ASSERTE(!"Should not be called");
        return NULL;
    }


#ifdef DACCESS_COMPILE
    virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
#endif
    
    // Heap Management functions
    static void NibbleMapSet(DWORD *pMap, size_t delta, BOOL bSet = TRUE);
    static size_t FindMethodCode(PTR_DWORD pMap, TADDR delta);

    inline virtual BYTE* GetNativeEntry(BYTE* startAddress)
    {
        LEAF_CONTRACT;
        return startAddress;
    }

/* =========== NOT CURRENTLY USED =====================
    void *NewNativeHeap(DWORD startAddr, DWORD length);
    BOOL IsJITforCurrentIP(DWORD currentPC);
   =========== NOT CURRENTLY USED ===================*/

#ifndef DACCESS_COMPILE
    void        ReleaseReferenceToHeap(CodeHeap *pCodeHeap, MethodDesc *pMD);
    void        ReleaseHeap(CodeHeap *pCodeHeap);
    void        DeleteCodeHeap(HeapList *pHeapList);
    void        RemoveCodeHeapFromDomainList(CodeHeap *pHeap, BaseDomain *pDomain);

#endif

private :
    struct DomainCodeHeapList {
        BaseDomain *m_pDomain;
        CDynArray<HeapList *> m_CodeHeapList;
        DomainCodeHeapList();
        ~DomainCodeHeapList();
    };
#ifndef DACCESS_COMPILE
    HeapList*   NewCodeHeap(CodeHeapRequestInfo *pInfo, DomainCodeHeapList *pADHeapList); 
    HeapList*   GetCodeHeap(CodeHeapRequestInfo *pInfo);
    void*       allocCodeRaw(CodeHeapRequestInfo *pInfo, 
                             size_t blockSize, unsigned align,
                             HeapList ** ppCodeHeap /* Writeback, Can be null */ );

    DomainCodeHeapList *GetCodeHeapList(MethodDesc *pMD, BaseDomain *pDomain);
    LoaderHeap* GetJitMetaHeap(MethodDesc *pMD);

protected :    
    void *      allocEHInfoRaw(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize);
private :       
#endif // #ifndef DACCESS_COMPILE

    static CodeHeader * GetCodeHeaderFromAddr(TADDR startAddress)
    {
        LEAF_CONTRACT;
        //return PTR_CodeHeader((PTR_HOST_TO_TADDR(startAddress) & ~3) - sizeof(CodeHeader));
        return PTR_CodeHeader((startAddress & ~3) - sizeof(CodeHeader));
    }

    PTR_HeapList m_pCodeHeap;

    PTR_HeapList GetVolatile_pCodeHeap()
    { return m_pCodeHeap; }
    
    void SetVolatile_pCodeHeap(PTR_HeapList value)
    { m_pCodeHeap = value; }
    
protected :    
    CrstExplicitInit    m_CodeHeapCritSec;
private :    
    EEJitDebugInfoStore m_DebugInfoStore;

    // must hold critical section to access this structure.
    CUnorderedArray<DomainCodeHeapList *, 5> m_DomainCodeHeaps;
    CUnorderedArray<DomainCodeHeapList *, 5> m_DynamicDomainCodeHeaps;

    // infrastructure to manage readers so we can lock them out and delete domain data
    volatile LONG        m_dwReaderCount;
    volatile LONG        m_dwWriterLock;

    MethodDesc* JitCodeToMethodDescWrapper( SLOT currentPC, 
                                            METHODTOKEN* pMethodToken=NULL, 
                                            DWORD* pPCOffset=NULL
                                            );

    void AddRangeToJitHeapCache (TADDR startAddr, TADDR endAddr, HeapList* pHp);
    void DeleteJitHeapCache (HeapList *pHeapList);
    size_t GetCodeHeapCacheSize (size_t bAllocationRequest);

    const static DWORD  HASH_BUCKETS       = 256;

    const static size_t CACHE_BLOCK_SIZE   = 0x00010000;                          // ( 64 KB )
    const static size_t CACHE_BLOCK_MASK   = CACHE_BLOCK_SIZE-1;                  // 0x0000ffff
    const static size_t CACHE_BLOCK_ALIGN  = ~CACHE_BLOCK_MASK;                   // 0xffff0000
    const static size_t CACHE_INDEX_MASK   = (HASH_BUCKETS-1) * CACHE_BLOCK_SIZE; // 0x00ff0000
    const static DWORD  CACHE_INDEX_RSHIFT = 16;

    inline DWORD GET_CACHE_INDEX(size_t addr)
    { return ((DWORD)(addr & CACHE_INDEX_MASK)) >> CACHE_INDEX_RSHIFT; }

    inline size_t COMPUTE_HASH_KEY(size_t addr)
    { return (addr & CACHE_BLOCK_ALIGN); }

    typedef struct _HashEntry
    {
        size_t hashKey;      // Key stored as COMPUTE_HASH_KEY(currentPC), hash is computed GET_CACHE_INDEX(hashKey)
        PTR_HeapList pHp;    // Value points to the HeapList's node
        DPTR(struct _HashEntry) pNext;
    } HashEntry;
    typedef DPTR(HashEntry) PTR_HashEntry;
    PTR_HashEntry m_JitCodeHashTable[HASH_BUCKETS];
    HashEntry *m_pJitHeapCacheUnlinkedList;
#ifdef _DEBUG
    BOOL DebugContainedInHeapList (HeapList *pHashEntryHp);
    void DebugCheckJitHeapCacheValidity ();
#endif // _DEBUG

    static void IncrementReader(EEJitManager *pMgr);
    static void DecrementReader(EEJitManager *pMgr);
    static void TakeWriter(EEJitManager *pMgr);
    static void ReleaseWriter(EEJitManager *pMgr);

    typedef DacHolder<EEJitManager *, EEJitManager::IncrementReader, EEJitManager::DecrementReader> ReaderLockHolder;
    typedef DacHolder<EEJitManager *, EEJitManager::TakeWriter, EEJitManager::ReleaseWriter> WriterLockHolder;
};


//*****************************************************************************
//
// This class manages IJitManagers and ICorJitCompilers.  It has only static
// members.  It should never be constucted.
//
//*****************************************************************************

#if defined (_MSC_VER) && _MSC_VER <= 1300
template void DoNothing(ExecutionManager*);
template BOOL CompareDefault(ExecutionManager*,ExecutionManager*);
typedef DacHolder<ExecutionManager *, DoNothing, DoNothing> HACKExecutionManagerLockHolder;
#endif

class ExecutionManager
{
    friend class CorExternalDataAccess;

#ifdef DACCESS_COMPILE
    friend class ClrDataAccess;
#endif

    friend bool decodeMethodEntryPoint(const BYTE* pBuffer, BYTE epSize, const BYTE** pTarget, SSIZE_T* pMDOffset, bool fHasLock);

    static IJitManager*   FindJitManNonZeroWrapper(SLOT currentPC);
    static IJitManager*   FindJitManNonZero(SLOT currentPC, IJitManager::ScanFlag scanFlag=IJitManager::ScanReaderLock);
public :

    static void Init();

    // this gets called a lot for stackwalking, so inline the zero case
    static IJitManager*   FindJitMan(SLOT currentPC, IJitManager::ScanFlag scanFlag=IJitManager::ScanReaderLock)
    {
        CONTRACTL {
            NOTHROW;
            GC_NOTRIGGER;
            SO_TOLERANT;
        } CONTRACTL_END;
 
        return (currentPC ? FindJitManNonZero(currentPC, scanFlag) : NULL);
    }

    static IJitManager*   FindJitManPCOnly(SLOT currentPC)
    {
        CONTRACTL {
            NOTHROW;
            GC_NOTRIGGER;
            SO_TOLERANT;
        } CONTRACTL_END;
 
        return (currentPC ? FindJitManNonZeroWrapper(currentPC) : NULL);
    }

    // Find a code manager from the current locations of the IP
    static ICodeManager*  FindCodeMan(SLOT currentPC, IJitManager::ScanFlag scanFlag=IJitManager::ScanReaderLock) 
    {
        CONTRACTL {
            NOTHROW;
            GC_NOTRIGGER;
            SO_TOLERANT;
        } CONTRACTL_END;
 
        IJitManager * pJitMan = FindJitMan(currentPC, scanFlag);
        return pJitMan != NULL ? pJitMan->GetCodeManager() : NULL;
    }

    // Use JitCodeToMethodOffset() to get the offset relative to the start of the method.
    static DWORD          JitCodeToOffset(TADDR currentPC);
        

    static IJitManager*   FindJitForType(DWORD Flags);
    static void ClearCaches( void );
    static BOOL IsCacheCleanupRequired();

    static LPWSTR         GetJitName();
    static IJitManager*   GetJitForType(DWORD Flags, bool dontLoadJit = false);

    static void           Unload(AppDomain *pDomain);
    static BOOL           PatchEntryPoint(BYTE* pBuffer, BYTE epSize, 
                                          BYTE* target, MethodDesc * methodDesc);

    static void           AddJitManager(IJitManager * newjitmgr);
    static RangeSection * AddCodeRange(TADDR StartRange, TADDR EndRange,
                                       IJitManager* pJit, TADDR Table,
                                       DWORD flags=0,
                                       RangeSection *pColdRangeSection=NULL,
                                       Module* pModule=NULL);
    static void           DeleteCodeRange(TADDR StartRange);
    static RangeSection * AddDataRange(TADDR StartRange, TADDR EndRange,
                                       Module* pModule=NULL);
    static void           DeleteDataRange(TADDR StartRange);

    static void           ReleaseReferenceToHeap(EEJitManager *pJitManager, CodeHeap *pCodeHeap, MethodDesc *pMethod);
    static void           ReleaseHeap(EEJitManager *pJitManager, CodeHeap *pCodeHeap);

#ifndef FJITONLY
    static ICodeManager*  GetDefaultCodeManager()
    {
        LEAF_CONTRACT;
        return (ICodeManager *)m_pDefaultCodeMan;    
    }
#endif

    static Module* FindZapModule(TADDR currentData);

    // NOTE: This will only work well for NGEN'd images
    static Module* FindZapModuleForNativeCode(TADDR currentCode);


    static RangeSection*             GetRangeSection(RangeSection *pRS, TADDR addr);
    static RangeSection*             GetRangeSectionAndPrev(RangeSection *pRS, TADDR addr, RangeSection **ppPrev);

    static RangeSection*             GetRangeSectionForAddress(TADDR startAddress);
        
#ifdef DACCESS_COMPILE
    static void EnumRangeList(RangeSection* list,
                              CLRDataEnumMemoryFlags flags);
    static void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
#endif

#ifndef DACCESS_COMPILE
    static void    preallocatedJumpStubBlock(BYTE * mem, DWORD blockSize, BaseDomain *pDomain);
    static void    unlinkPreallocatedJumpStubBlock(BYTE * mem, DWORD blockSize, BaseDomain *pDomain);
    static void    deleteJumpStubBlock(HeapList *pHeapList);
    static void    deleteJumpStubBlockHelper(TADDR startAddr, TADDR endAddr);

    static JumpStubBlockHeader * recoverJumpStubBlockHeader(BYTE * jumpStub);

    static BYTE *  jumpStub(MethodDesc* pMD,
                            BYTE * target,
                            BYTE * loAddr,
                            BYTE * hiAddr,
                            BaseDomain *pDomain = NULL);
#endif
    
private : 

    SPTR_DECL(RangeSection,  m_CodeRangeList);
    SPTR_DECL(RangeSection,  m_DataRangeList);
    SPTR_DECL(IJitManager,   m_pJitList);
#ifndef FJITONLY
    SPTR_DECL(EECodeManager, m_pDefaultCodeMan);
#endif
    static CrstStatic       m_ExecutionManagerCrst;
    static CrstStatic       m_JumpStubCrst;
    static CrstStatic       m_RangeCrst;        // Aquire before writing into m_CodeRangeList and m_DataRangeList
    static BYTE             m_fFailedToLoad;

    // infrastructure to manage readers so we can lock them out and delete domain data
    // make ReaderCount volatile because we have order dependency in READER_INCREMENT
#ifndef DACCESS_COMPILE
    static volatile LONG   m_dwReaderCount;
    static volatile LONG   m_dwWriterLock;
#else
    SVAL_DECL(LONG, m_dwReaderCount);
    SVAL_DECL(LONG, m_dwWriterLock);
#endif

#ifdef DACCESS_COMPILE
    static bool IsSafe(void)
    {
        return m_dwWriterLock == 0;
    }
#endif
    
    static void IncrementReader(ExecutionManager *pMgr);
    static void DecrementReader(ExecutionManager *pMgr);
    static void TakeWriter(ExecutionManager *pMgr);
    static void ReleaseWriter(ExecutionManager *pMgr);

    typedef DacHolder<ExecutionManager *, ExecutionManager::IncrementReader, ExecutionManager::DecrementReader, 0, NoNull<ExecutionManager *> > ReaderLockHolder; 
    typedef DacHolder<ExecutionManager *, ExecutionManager::TakeWriter, ExecutionManager::ReleaseWriter, 0, NoNull<ExecutionManager *> > WriterLockHolder; 

    static RangeSection * AddRangeHelper(RangeSection** ppRangeList,
                                         TADDR StartRange,
                                         TADDR EndRange,
                                         IJitManager* pJit, 
                                         TADDR Table, 
                                         DWORD flags=0, 
                                         RangeSection *pColdRangeSection=NULL,
                                         Module* pModule=NULL);
    static void DeleteRangeHelper(RangeSection** ppRangeList,
                                  TADDR StartRange);

#ifndef DACCESS_COMPILE
    static BYTE * getNextJumpStub(MethodDesc* pMD,
                                  IJitManager* pJitMan,
                                  BYTE * target,
                                  BYTE * loAddr,  BYTE * hiAddr,
                                  BaseDomain *pDomain);
#endif    

private:
    static JumpStubBlockHeader *  m_jumpStubBlock;

    // ***************************************************************************
    // Hashtable for JumpStubs for jitted code

    struct JumpStubEntry {
        BYTE*       m_target;
        BYTE*       m_jumpStub;
    };

    class JumpStubTraits : public DefaultSHashTraits<JumpStubEntry>
    {
    public:
        typedef BYTE* key_t;

        static key_t GetKey(element_t e)
        {
            LEAF_CONTRACT;
            return e.m_target;
        }
        static BOOL Equals(key_t k1, key_t k2)
        {
            LEAF_CONTRACT;
            return k1 == k2;
        }
        static count_t Hash(key_t k)
        {
            LEAF_CONTRACT;
            return (count_t)(size_t)k;
        }

        static const element_t Null() { LEAF_CONTRACT; JumpStubEntry e; e.m_target = NULL; return e; }
        static bool IsNull(const element_t &e) { LEAF_CONTRACT; return e.m_target == NULL; }
        static const element_t Deleted() { LEAF_CONTRACT; JumpStubEntry e; e.m_target = (BYTE*)-1; return e; }
        static bool IsDeleted(const element_t &e) { LEAF_CONTRACT; return e.m_target == (BYTE*)-1; }
    };
    typedef SHash<JumpStubTraits> JumpStubTable;

    static JumpStubTable *        m_jumpStubTable;
};

//-----------------------------------------------------------------------------
    
inline
/* static */ DWORD ExecutionManager::JitCodeToOffset(TADDR currentPC)
{
    CONTRACTL {
        NOTHROW;
        GC_NOTRIGGER;
    } CONTRACTL_END;

    DWORD offset;
    IJitManager *pJitMan = FindJitMan((SLOT)currentPC);
    _ASSERTE(pJitMan != NULL);

    pJitMan->JitCodeToMethodInfo((SLOT)currentPC, 
                                 NULL, 
                                 NULL, 
                                 &offset
                                 );
    return offset;
}
        

//-----------------------------------------------------------------------------
// this is only called from a couple of places, but inlining helps EH perf

inline void* EEJitManager::GetGCInfo(METHODTOKEN MethodToken)
{
    CONTRACTL {
        NOTHROW;
        GC_NOTRIGGER;
    } CONTRACTL_END;

    CodeHeader* pHeader = MethodToken->GetCodeHeader();

    return pHeader->GetGCInfo();
}

inline BYTE* EEJitManager::JitTokenToStartAddress(METHODTOKEN MethodToken, IJitManager::ScanFlag scanFlag)
{
    CONTRACTL {
        NOTHROW;
        GC_NOTRIGGER;
    } CONTRACTL_END;

    return JitTokenToStartAddressStatic(MethodToken, scanFlag);
}

inline BYTE* EEJitManager::JitTokenToStartAddressStatic(METHODTOKEN MethodToken, IJitManager::ScanFlag scanFlag)
{ 
    CONTRACTL {
        NOTHROW;
        GC_NOTRIGGER;
        WIN64_ONLY(PRECONDITION(!MethodToken->IsFuncletMethodToken()));
    } CONTRACTL_END;

    if (MethodToken)
    {
        return MethodToken->GetCodeHeader()->GetCodeStartAddress();
    }
    return NULL;
}

inline size_t EEJitManager::JitTokenToMethodHotSize(METHODTOKEN MethodToken)
{
    CONTRACTL {
        NOTHROW;
        GC_NOTRIGGER;
    } CONTRACTL_END;

    return GetCodeManager()->GetFunctionSize(GetGCInfo(MethodToken));
}

inline void EEJitManager::JitTokenToMethodRegionInfo(METHODTOKEN MethodToken, MethodRegionInfo *methodRegionInfo)
{
    CONTRACTL {
        NOTHROW;
        GC_NOTRIGGER;
        PRECONDITION(methodRegionInfo != NULL);
        WIN64_ONLY(PRECONDITION(!MethodToken->IsFuncletMethodToken()));
    } CONTRACTL_END;

    methodRegionInfo->hotStartAddress  = JitTokenToStartAddress(MethodToken);
    methodRegionInfo->hotSize          = JitTokenToMethodHotSize(MethodToken);
    methodRegionInfo->coldStartAddress = 0;
    methodRegionInfo->coldSize         = 0;
}


//-----------------------------------------------------------------------------

//*****************************************************************************
// Implementation of the ICodeInfo interface

class EECodeInfo : public ICodeInfo
{
public:

    EECodeInfo(METHODTOKEN token, IJitManager * pJM);
    EECodeInfo(METHODTOKEN token, IJitManager * pJM, MethodDesc * pMD);

    const char*  __stdcall getMethodName(const char **moduleName /* OUT */ );
    void         __stdcall getMethodSig(CORINFO_SIG_HANDLE    *phsig,     /* OUT */
                                        DWORD                 *pcbSigSize,/* OUT */
                                        CORINFO_MODULE_HANDLE *phscope);  /* OUT */
    virtual LPVOID       __stdcall getStartAddress();
    IJitManager* __stdcall getJitManager() { LEAF_CONTRACT; return m_pJM; };
    bool         __stdcall IsSynchronized();
    bool         __stdcall AcquiresInstMethodTableFromThis();
    bool         __stdcall RequiresInstArg();

    METHODTOKEN         m_methodToken;
    MethodDesc         *m_pMD;
    IJitManager        *m_pJM;

    static inline CEEInfo* GetCEEInfo()
        { LEAF_CONTRACT;  return (CEEInfo*)&s_ceeInfoMemory; }
    static BYTE s_ceeInfoMemory[sizeof(CEEInfo)];

#ifndef DACCESS_COMPILE
    static void Init();
#endif
};

#endif // !__CODEMAN_HPP__

